package com.college.common.utils.security;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.NoSuchAlgorithmException;
import java.security.Permission;
import java.security.PermissionCollection;
import java.util.Map;

public class AesCbcPk5Util {
    private static final String ALGORITHM = "AES/CBC/PKCS5Padding";

    static {
        UnlimitedKeyStrengthJurisdictionPolicy.ensure();
    }

    public static byte[] encrypt(byte[] srcData, byte[] key, byte[] iv) throws Exception {
        Cipher.getMaxAllowedKeyLength(ALGORITHM);
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(iv));
        return cipher.doFinal(srcData);
    }

    public static String encryptStr(String srcDataStr, String keyStr, String ivStr)  {
        String key = keyStr.length() < 16 ? FillCode(keyStr, 16, "0", 0) : keyStr;
        byte[] iv = new byte[16];
        try {
            System.arraycopy(ivStr.getBytes("UTF-8"), 0, iv, 0, iv.length);
            return removeRNT(Base64.encodeBase64String(encrypt(srcDataStr.getBytes("UTF-8"), key.getBytes("UTF-8"), iv)));
        }  catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static byte[] decrypt(byte[] encData, byte[] key, byte[] iv) throws Exception {
        Cipher.getMaxAllowedKeyLength(ALGORITHM);
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(iv));
        return cipher.doFinal(encData);
    }

    public static String decryptStr(String srcDataStr, String keyStr, String ivStr) throws Exception {
        String key = keyStr.length() < 16 ? FillCode(keyStr, 16, "0", 0) : keyStr;
        byte[] iv = new byte[16];
        System.arraycopy(ivStr.getBytes("UTF-8"), 0, iv, 0, iv.length);
        return new String(decrypt(Base64.decodeBase64(srcDataStr), key.getBytes("UTF-8"), iv), "UTF-8");

    }

    private static String removeRNT(String originalStr) {
        if (originalStr == null || originalStr.isEmpty()) {
            return originalStr;
        }
        return originalStr.replaceAll("[\t\n\r]", "");
    }

    public static String FillCode(String data, int max_length, String fill, int direction) {
        if (data != null && !data.equals("")) {
            String val = "";
            int length = 0;
            for (int i = 0; i < data.length(); i++) {
                length += 1;
            }
            for (int i = 0; i < (max_length - length); i++) {
                val += fill != null ? fill : " ";
            }
            if (length > max_length)
                data = data.substring(0, max_length);
            if (direction == 0)
                data = val + data;
            else if (direction == 1)
                data = data + val;
        }
        return data;
    }

    public static void main(String[] args) throws Exception {
        String appId = "YLX001";
        String appSecret = "cc15ce4ddde64eb11e8139be4b172248";
        String context = "tDL5nC2n/TTDtLd4Q793Kg==";
        System.out.println(decryptStr(context, appId, appSecret));
    }

}
class UnlimitedKeyStrengthJurisdictionPolicy {
    private static boolean isRestrictedCryptography() throws NoSuchAlgorithmException {
        return Cipher.getMaxAllowedKeyLength("AES/ECB/NoPadding") <= 128;
    }

    private static void removeCryptographyRestrictions() {
        try {
            if (!isRestrictedCryptography()) {
                return;
            }

            Class<?> jceSecurity = Class.forName("javax.crypto.JceSecurity");
            Class<?> cryptoPermissions = Class.forName("javax.crypto.CryptoPermissions");
            Class<?> cryptoAllPermission = Class.forName("javax.crypto.CryptoAllPermission");

            Field isRestrictedField = jceSecurity.getDeclaredField("isRestricted");
            isRestrictedField.setAccessible(true);
            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(isRestrictedField, isRestrictedField.getModifiers() & ~Modifier.FINAL);
            isRestrictedField.set(null, false);

            Field defaultPolicyField = jceSecurity.getDeclaredField("defaultPolicy");
            defaultPolicyField.setAccessible(true);
            PermissionCollection defaultPolicy = (PermissionCollection) defaultPolicyField.get(null);

            Field perms = cryptoPermissions.getDeclaredField("perms");
            perms.setAccessible(true);
            ((Map<?, ?>) perms.get(defaultPolicy)).clear();

            Field instance = cryptoAllPermission.getDeclaredField("INSTANCE");
            instance.setAccessible(true);
            defaultPolicy.add((Permission) instance.get(null));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static {
        removeCryptographyRestrictions();
    }

    public static void ensure() {
        // just force loading of this class
    }
}

